package com.hfzy.ihk.web.ivr.support.callin.handler;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.hfzy.ihk.common.constants.GlobalStatic;
import com.hfzy.ihk.common.eventSocket.constant.EventSubClassName;
import com.hfzy.ihk.common.eventSocket.enums.EventName;
import com.hfzy.ihk.common.util.date.DateUtils;
import com.hfzy.ihk.common.util.string.StringTools;
import com.hfzy.ihk.common.util.string.StringUtil;
import com.hfzy.ihk.facade.ivr.vo.FreeswitchCallState;
import com.hfzy.ihk.web.ivr.biz.FreeswitchAsrCallStateBiz;
import com.hfzy.ihk.web.ivr.biz.PushDataToEsBiz;
import com.hfzy.ihk.web.ivr.biz.PushDataToOracleBiz;
import com.hfzy.ihk.web.ivr.constant.*;
import com.hfzy.ihk.web.ivr.context.EventSocketInitBean;
import com.hfzy.ihk.web.ivr.support.callin.event.FreeswitchCallStateEvent;
import com.hfzy.ihk.web.ivr.support.disruptor.base.DisruptorHandlerAdapter;
import com.hfzy.ihk.web.ivr.websocket.WebSocketUtils;
import org.freeswitch.esl.client.transport.SendMsg;
import org.freeswitch.esl.client.transport.event.EslEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Scope;
import org.springframework.core.task.TaskExecutor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import static org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED;


/**
 * Created by Administrator on 2019/6/5.
 */
@Component
@Scope("prototype")
public class FreeswitchAsrCallStateHandler implements DisruptorHandlerAdapter<FreeswitchCallStateEvent> {

    Logger logger = LoggerFactory.getLogger(FreeswitchAsrCallStateHandler.class);

    @Autowired(required = false)
    RestTemplate restTemplate;

    @Autowired
    RedisTemplate redisTemplate;

    @Autowired
    WebSocketUtils webSocketUtils;

    @Resource
    TaskExecutor pushDataToEsTaskExecutor;

    @Resource
    TaskExecutor pushDataToOracleTaskExecutor;

    @Autowired
    FreeswitchAsrCallStateBiz freeswitchAsrCallStateBiz;

    @Autowired
    PushDataToEsBiz pushDataToEsBiz;

    @Autowired
    PushDataToOracleBiz pushDataToOracleBiz;

    @Value("${freeswitch.web.recordFileUrl}")
    private String  recordFileUrl;

    @Value("${freeswitch.web.url}")
    private String serverUrl;

    @Value("${freeswitch.recordFileDiskPath}")
    private String recordFilePath;

    @Value("${linkcall.web.url}")
    private String linkcallWebUrl;

    @Autowired
    private EventSocketInitBean eventInitBean;

    @Override
    public void onEvent(FreeswitchCallStateEvent event, long sequence, boolean endOfBatch) throws Exception {
        try {
            Long old = System.currentTimeMillis();

            // procces(event.getData());

            old = System.currentTimeMillis()-old;
            logger.debug("ivr eventHandler handle use time:{}",old);
        } catch (Exception e) {
            logger.error("ivr FreeswitchCallStateHandler exception",e);
        }
    }

    @Override
    public void onEvent(FreeswitchCallStateEvent event) throws Exception {
        try {
            Long old = System.currentTimeMillis();

            procces(event.getData());

            old = System.currentTimeMillis()-old;
            logger.debug("ivr workHandler handle use time:{}",old);
        } catch (Exception e) {
            logger.error("ivr FreeswitchCallStateHandler exception",e);
        }
    }

    /**
     * 流程方法
     * 1、跟进sessionId从redis读取callHistory
     * 2、如果存在，更新callHistory状态（判断状态逻辑），状态发送到websocketServer
     * 3、更新redis
     * 4、进入批量插入队列
     *
     * @param state*/
    protected void procces(FreeswitchCallState state){

        Map<String,String> callHistoryMap = null;
        /*读不到，就不管了，不能影响状态返回*/

        try {
            callHistoryMap = readRedis(state.getSessionId());
            logger.debug("ivr read redis callHistoryMap:{}", JSONObject.toJSONString(callHistoryMap));
        } catch (Exception e) {
            logger.error("ivr --> readRedis Failed! sessionId:{}",state.getSessionId());
            handleReadRedisFailed(state);
        }

        Map<String,Map<String,String>> resultMap = null;

        try {
            //分析状态
            //双呼
            if(!state.getEvent().getEventHeaders().containsKey("variable_sip_h_goto_robot")){
                resultMap = analyzeCallState(state,callHistoryMap);
            }else{//单呼
                resultMap = analyzeAsrCallState(state,callHistoryMap);
            }

        } catch (Exception e) {
            e.printStackTrace();
            logger.error("analyzeCallState Failed!sessionId:{}",state.getSessionId());
        }

        try {
            //将状态推送到客户端
            pushStateToClient(callHistoryMap,resultMap);
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("ivr-->pushStateToClient Failed!sessionId:{}",state.getSessionId());
        }

        try {
            /*写入呼叫状态*/
            writeRedis(state.getSessionId(),resultMap.get(Constants.CALL_STATE_WORK_HANDLER_MAP_KEY_REDIS));
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("ivr-->writeRedis Failed! sessionId:{}",state.getSessionId());
        }

        boolean check = false;

        try {
            logger.debug("ivr-->resultMap.get(Constants.CALL_STATE_WORK_HANDLER_MAP_KEY_REDIS):{}", JSONObject.toJSONString(resultMap.get(Constants.CALL_STATE_WORK_HANDLER_MAP_KEY_REDIS)));
            if(resultMap.get(Constants.CALL_STATE_WORK_HANDLER_MAP_KEY_REDIS).isEmpty())
                return;
            //合并一下map（redis+当前的)
            callHistoryMap.putAll(resultMap.get(Constants.CALL_STATE_WORK_HANDLER_MAP_KEY_REDIS));
            //状态来到时，判断下是否需要推送到ES 进行入库
            check = checkCanOrNotPushToBatchInsertQueue(callHistoryMap,resultMap.get(Constants.CALL_STATE_WORK_HANDLER_MAP_KEY_REDIS),state);
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("ivr--> checkCanOrNotPushToBatchInsertQueue Failed! sessionId:{}",state.getSessionId());
            check = false;
        }
        //如果需要则将呼叫记录推送到ES 保存
        if(check){
            logger.debug("ivr-->start pulishToBatchInsert,sessionId:{}", state.getSessionId());
            todoSaveCallRcord(callHistoryMap);

            //这里需要做个特殊，将新版crm的呼叫记录(whereFrom=5)推送到置业的Oracle
            logger.info(">>>>>>>>>>>>>开始推送置业Oracle数据-------commitTo:{}",callHistoryMap.get(RedisFields.CALL_HISTORY_COMMIT_TO));
            pushCallRcordToOracle(callHistoryMap);

        }
        //流程结束

    }

    /**
     * 读取redis
     *
     * @param sessionId
     * @return
     */
    private Map<String, String> readRedis(String sessionId) {

        logger.debug("FreeswitchCallStateWorkHandler readRedis：" + sessionId);

        Map<String,String> redisMap = redisTemplate.opsForHash().entries(RedisKey.CALL_HISTORY_RPIX + sessionId);

        return redisMap;
    }

    protected String writeRedis(String sessionId, Map<String, String> map) {
        if (map.isEmpty()) {
            logger.debug("freeswitchCallStateHandler--->writeRedis --->map is Empty,");
            return Constants.FAIL;
        }
        redisTemplate.opsForHash().putAll(RedisKey.CALL_HISTORY_RPIX + sessionId, map);
        return Constants.SUCCESS;
    }

    private String handleReadRedisFailed(FreeswitchCallState Data) {
        return null;
    }

    private boolean checkCanOrNotPushToBatchInsertQueue(Map<String, String> callHistoryMap, Map<String, String> redisMap, FreeswitchCallState data) {
        boolean ableInsert = false;
        if (data.getMsgType().equals(AliyunAkInfo.VOICEREPORT)) {
            ableInsert = true;
        }
        return ableInsert;
    }

    /**
     * 单呼呼出客户接通播放开场白
     * @param callHistoryMap
     */
    private void playRecording(String sessionId,Map<String, String> callHistoryMap){
        if (callHistoryMap.containsKey(RedisFields.VOICE_CODE) && StringTools.isNotempty(callHistoryMap.get(RedisFields.VOICE_CODE))) {
            try {
                eventInitBean.getClient().sendBackgroundApiCommand("uuid_playback", sessionId+" file_string://"+callHistoryMap.get(RedisFields.VOICE_CODE).toString());
            }catch (Exception e){
                logger.error("播放开场白失败，sessionId:{},错误信息：{}",sessionId,e);
            }
        }
        if (callHistoryMap.containsKey(RedisFields.VOICE_TEXT) && StringTools.isNotempty(callHistoryMap.get(RedisFields.VOICE_TEXT))) {
            //开场白文字信息发送到浏览器
            freeswitchAsrCallStateBiz.pushSpeechAnalysisToBrowser("A",sessionId,callHistoryMap.get(RedisFields.VOICE_TEXT));
        }
    }

    /**
     * 自义定事件推送客户端的状态
     * @param subclass
     * @param msgMap
     * @param redisSaveMap
     */
    private void freeswitchCustomEvent(String subclass,Map<String,String> msgMap,Map<String,String> redisSaveMap){
        switch (subclass){
            case EventSubClassName.DIAL_GATEWAY_NOT_REGISTER:
                logger.info("ivr >>fs网关未注册");
                msgMap.put(Constants.WEB_SOCKET_JSON_KEY_MSG_TYPE, Constants.WEB_SOCKET_MSG_TYPE_GATEWAY_NOT_REGISTERED);
                redisSaveMap.put(RedisFields.CALL_HISTORY_FAILED_REASON, "网关未注册");
                break;
            case EventSubClassName.DIAL_LINE_BUSY:
                logger.info("ivr >>fs线路忙");
                msgMap.put(Constants.WEB_SOCKET_JSON_KEY_MSG_TYPE, Constants.WEB_SOCKET_MSG_TYPE_LINE_BUSY);
                redisSaveMap.put(RedisFields.CALL_HISTORY_FAILED_REASON, "线路忙");
                break;
            default:
                //多余状态不推送到客户端
                msgMap.put(Constants.WEB_SOCKET_JSON_KEY_MSG_TYPE, Constants.WEB_SOCKET_MSG_TYPE_INVALID);
                break;
        }
    }

    /**
     * 分析单呼呼出呼入状态
     *
     * @param callState
     * @param callHistoryMap
     * @return
     * @throws Exception
     */
    private Map<String, Map<String, String>> analyzeAsrCallState(FreeswitchCallState callState, Map<String, String> callHistoryMap) throws Exception {


        logger.info("ivr analyzeAsr callState:" + JSON.toJSONString(callState));
        logger.info("ivr analyzeAsr callHistoryMap:" + JSON.toJSONString(callHistoryMap));
        //eventName
        EventName eventName = EventName.fromName(callState.getStatus_code());
        //取出event
        EslEvent event = callState.getEvent();

        Map<String, Map<String, String>> resultMap = new HashMap<>(2);
        //返回给客户端的map
        Map<String, String> msgMap = new HashMap<>(2);
        Map<String, String> redisSaveMap = new HashMap<>();

        String nowDateStr = DateUtils.formatDate(new Date(), DateUtils.DATE_FORMAT_DATETIME_SSS);

        if (callState.getMsgType().equals(AliyunAkInfo.VOICECALLREPORT)) { //呼出中间状态
            switch (eventName) {
                case CHANNEL_PROGRESS:  //用户响铃 该状态不用推送给客户端
                        redisSaveMap.put(RedisFields.CALL_HISTORY_MAIN_CALL_RINGING_TIME, DateUtils.stringFromString(callState.getStatus_time(), DateUtils.DATE_FORMAT_DATETIME_SSS));
                        redisSaveMap.put(RedisFields.CALL_HISTORY_MAIN_CALL_RINGING, Constants.TRUE);
                        redisSaveMap.put(RedisFields.RECEIVE_CALL_HISTORY_MAIN_CALL_RINGING_TIME, nowDateStr);
                        msgMap.put(Constants.WEB_SOCKET_JSON_KEY_MSG_TYPE, Constants.WEB_SOCKET_MSG_TYPE_INVALID);
                    break;

                case CHANNEL_ANSWER:
                        /*单呼接通播放开场白*/
                        //呼出
                        if(callHistoryMap.containsKey(RedisFields.CALL_HISTORY_CALL_TYPE)&&Constants.CALL_OUT.toString().equals(callHistoryMap.get(RedisFields.CALL_HISTORY_CALL_TYPE))){
                            playRecording(callState.getSessionId(),callHistoryMap);
                        }else{//呼入
                            logger.info("单呼呼入查询开场白，packageId:{}",callHistoryMap.get(RedisFields.PACKAGE_ID));
                            if(callHistoryMap.containsKey(RedisFields.PACKAGE_ID)){
                                Map<String,String> map = getVoiceMapByPackageId(callHistoryMap.get(RedisFields.PACKAGE_ID));
                                playRecording(callState.getSessionId(),map);
                            }else{
                                //没有packageId处理,先拿到packageId在查询开场白

                            }
                        }

                        logger.info("freeswitch单呼开始进行录音: sessionId:" + callState.getOut_id() + " 主叫:" + callState.getCaller());
                        String result = startRecord(callState.getOut_id());

                        if (result.equals(GlobalStatic.FAIL)) {
                            logger.info("freeswitch单呼录音异常: sessionId:" + callState.getOut_id() + " 主叫:" + callState.getCaller());
                        }

                        msgMap.put(Constants.WEB_SOCKET_JSON_KEY_MSG_TYPE, Constants.WEB_SOCKET_MSG_TYPE_MAIN_ANSWERED);
                        redisSaveMap.put(RedisFields.CALL_HISTORY_MAIN_CALL_ANSWERED, Constants.TRUE);
                        redisSaveMap.put(RedisFields.CALL_HISTORY_MAIN_CALL_ANSWERED_TIME, DateUtils.stringFromString(callState.getStatus_time(), DateUtils.DATE_FORMAT_DATETIME_SSS));
                        redisSaveMap.put(RedisFields.RECEIVE_HISTORY_MAIN_CALL_ANSWERED_TIME, nowDateStr);

                    break;

                case CHANNEL_HANGUP:   //呼叫结束 返回的呼叫状态
                    //客户不接->客户无接听
                    //客户挂断->客户挂机
                    //客户接->结束通话
                    try {
                        //通话结束状态回来以后将该使用用户的繁忙状态改为否
                        if (callHistoryMap.get(RedisFields.CREATE_USER_ID) != null) {
                            redisTemplate.opsForHash().put(RedisKey.USER_BUSY, callHistoryMap.get(RedisFields.CREATE_USER_ID), Constants.FALSE);
                        }
                        redisSaveMap.put(RedisFields.CALL_HISTORY_DISCONNECT_TIME, DateUtils.stringFromString(callState.getStatus_time(), DateUtils.DATE_FORMAT_DATETIME_SSS));
                        redisSaveMap.put(RedisFields.RECEIVE_CALL_HISTORY_DISCONNECT_TIME, nowDateStr);

                        if (!Constants.TRUE.equals(callHistoryMap.get(RedisFields.CALL_HISTORY_MAIN_CALL_ANSWERED))) { //呼叫客户失败，（各种原因）

                            msgMap.put(Constants.WEB_SOCKET_JSON_KEY_MSG_TYPE, Constants.WEB_SOCKET_MSG_TYPE_MAIN_FAILED);
                            msgMap.put(Constants.WEB_SOCKET_JSON_KEY_DESC, Constants.FJ_TELECOM_FAILED_REASON_MAIN_FAILED_5);

                            redisSaveMap.put(RedisFields.CALL_HISTORY_MAIN_CALL_FAILED, Constants.TRUE);
                            redisSaveMap.put(RedisFields.CALL_HISTORY_MAIN_CALL_FAILED_TIME, DateUtils.stringFromString(callState.getStatus_time(), DateUtils.DATE_FORMAT_DATETIME_SSS));
                            redisSaveMap.put(RedisFields.RECEIVE_CALL_HISTORY_MAIN_CALL_FAILED_TIME, nowDateStr);

                        } else { //正常通话结束
                            msgMap.put(Constants.WEB_SOCKET_JSON_KEY_MSG_TYPE, Constants.WEB_SOCKET_MSG_TYPE_MAIN_DISCONNECTED);

                            //这里生产录音url ，因为只有正常通话才有录音
                            try {
                                Object recordFilePath = redisTemplate.opsForHash().get(RedisKey.CALL_HISTORY_RPIX + callState.getSessionId() + "_temp", "recordFilePath");

                                if (StringUtil.isNotNull(recordFilePath)) { //不为空有文件，将Url 放入redis
                                    redisSaveMap.put(RedisFields.CALL_HISTORY_RECORD_FILE_URL, serverUrl + recordFileUrl + recordFilePath);
                                    logger.info("freeswitchLog :  生成freeswitch录音文件url:" + serverUrl + recordFileUrl + recordFilePath);
                                    redisTemplate.delete(RedisKey.CALL_HISTORY_RPIX + callState.getSessionId() + "_temp");//取了以后删除key
                                }
                            }catch (Exception e){
                                logger.error(">>>生成录音文件url异常");
                            }

                        }

                    } catch (Exception e) { //防止话单比结束状态早回来的情况
                        msgMap.put(Constants.WEB_SOCKET_JSON_KEY_MSG_TYPE, Constants.WEB_SOCKET_MSG_TYPE_MAIN_DISCONNECTED);
                    }

                    break;
                case CUSTOM:
                    String subclass = event.getEventHeaders().get("Event-Subclass");
                    freeswitchCustomEvent(subclass,msgMap,redisSaveMap);
                    break;
                default:
                    //多余状态不推送到客户端
                    msgMap.put(Constants.WEB_SOCKET_JSON_KEY_MSG_TYPE, Constants.WEB_SOCKET_MSG_TYPE_INVALID);
                    break;

            }

            //如果中断，后续的数据不发送到客户端
            if (redisTemplate.opsForValue().get(RedisKey.INTERRUPT_FAIL + callHistoryMap.get(RedisFields.CALL_HISTORY_SESSION_ID)) != null) {

                redisSaveMap.put(RedisFields.CALL_HISTORY_REMARK, Constants.LOCAL_MSG_CALL_CANCEL);
                msgMap.put(Constants.WEB_SOCKET_JSON_KEY_MSG_TYPE, Constants.WEB_SOCKET_MSG_TYPE_INVALID);
            }


        } else if (callState.getMsgType().equals(AliyunAkInfo.VOICEREPORT)) {//呼出话务单话务单回来之后才推送给持久化服务


            //手动取消外呼显示取消外呼
            logger.info("fscall------------------INTERRUPT：{}", callHistoryMap.get(RedisFields.INTERRUPT));

            if (callHistoryMap.get(RedisFields.INTERRUPT) != null
                    && Constants.INTERRUPT.toString().equals(callHistoryMap.get(RedisFields.INTERRUPT))) {
                redisSaveMap.put(RedisFields.CALL_HISTORY_FAILED_REASON, Constants.LOCAL_MSG_CALL_CANCEL);

            }

            if (StringTools.isNotempty(callState.getA_duration())) { //主叫时长

                redisSaveMap.put(RedisFields.MAIN_CALL_LENGTH, callState.getA_duration());

                //通话时长,目前取主叫的通话时长（所有主叫均为客户）
                redisSaveMap.put(RedisFields.CALL_HISTORY_RECORD_TIME_LENTH, callState.getA_duration());

            }

            if (StringTools.isNotempty(callState.getA_start_time())) { // 主叫开始时间可

                redisSaveMap.put(RedisFields.MAIN_CALL_START_TIME, callState.getA_start_time());
            }

            if (StringTools.isNotempty(callState.getA_end_time())) { // 主叫结束时间

                redisSaveMap.put(RedisFields.MAIN_CALL_END_TIME, callState.getA_end_time());
            }

            //话务单回来也不需要发送到客户端
            msgMap.put(Constants.WEB_SOCKET_JSON_KEY_MSG_TYPE, Constants.WEB_SOCKET_MSG_TYPE_INVALID);

        }

        msgMap.put(Constants.WEB_SOCKET_JSON_KEY_TIME, nowDateStr);
        msgMap.put(Constants.WEB_SOCKET_JSON_KEY_SESSION_ID, callState.getSessionId());
        msgMap.put(Constants.WEB_SOCKET_JSON_KEY_DATA_ID, callHistoryMap.get(RedisFields.CALL_HISTORY_DATA_ID));
        msgMap.put(Constants.WEB_SOCKET_JSON_KEY_PAGE_FROM, callHistoryMap.get(RedisFields.CALL_HISTORY_PAGE_FROM));
        msgMap.put(Constants.WEB_SOCKET_JSON_KEY_MACHINE_FROM, callHistoryMap.get(RedisFields.CALL_HISTORY_MACHINE_FROM));

        resultMap.put(Constants.CALL_STATE_WORK_HANDLER_MAP_KEY_MSG, msgMap);
        resultMap.put(Constants.CALL_STATE_WORK_HANDLER_MAP_KEY_REDIS, redisSaveMap);

        return resultMap;

    }

    /**
     * 分析双呼呼入状态
     *
     * @param callState
     * @param callHistoryMap
     * @return
     * @throws Exception
     */
    private Map<String, Map<String, String>> analyzeCallState(FreeswitchCallState callState, Map<String, String> callHistoryMap) throws Exception {


        logger.info("ivr analyze callState:" + JSON.toJSONString(callState));
        logger.info("ivr analyze callHistoryMap:" + JSON.toJSONString(callHistoryMap));
        //eventName
        EventName eventName = EventName.fromName(callState.getStatus_code());
        //取出event
        EslEvent event = callState.getEvent();

        Map<String, Map<String, String>> resultMap = new HashMap<>(2);
        //返回给客户端的map
        Map<String, String> msgMap = new HashMap<>(2);
        Map<String, String> redisSaveMap = new HashMap<>();

        String nowDateStr = DateUtils.formatDate(new Date(), DateUtils.DATE_FORMAT_DATETIME_SSS);

        if (callState.getMsgType().equals(AliyunAkInfo.VOICECALLREPORT)) { //呼出中间状态
            switch (eventName) {
                case CHANNEL_PROGRESS:  //用户响铃 该状态不用推送给客户端

                    if (callState.getDestinationNumber().equals(callState.getCaller())) {

                        redisSaveMap.put(RedisFields.CALL_HISTORY_MAIN_CALL_RINGING_TIME, DateUtils.stringFromString(callState.getStatus_time(), DateUtils.DATE_FORMAT_DATETIME_SSS));
                        redisSaveMap.put(RedisFields.CALL_HISTORY_MAIN_CALL_RINGING, Constants.TRUE);
                        redisSaveMap.put(RedisFields.RECEIVE_CALL_HISTORY_MAIN_CALL_RINGING_TIME, nowDateStr);
                        msgMap.put(Constants.WEB_SOCKET_JSON_KEY_MSG_TYPE, Constants.WEB_SOCKET_MSG_TYPE_INVALID);

                    } else if (callState.getDestinationNumber().equals(callState.getCallee())) { //被叫响铃

                        redisSaveMap.put(RedisFields.CALL_HISTORY_TARGET_CALL_RINGING_TIME, DateUtils.stringFromString(callState.getStatus_time(), DateUtils.DATE_FORMAT_DATETIME_SSS));
                        redisSaveMap.put(RedisFields.CALL_HISTORY_TARGET_CALL_RINGING, Constants.TRUE);
                        redisSaveMap.put(RedisFields.RECEIVE_CALL_HISTORY_TARGET_CALL_RINGING_TIME, nowDateStr);
                        msgMap.put(Constants.WEB_SOCKET_JSON_KEY_MSG_TYPE, Constants.WEB_SOCKET_MSG_TYPE_INVALID);

                    }
                    break;

                case CHANNEL_ANSWER:

                    if (callState.getDestinationNumber().equals(callState.getCaller())) {//主叫接通,正在接通被叫 ---当做主叫接通和被叫响铃时间

                        logger.info("freeswitch开始进行录音: sessionId:" + callState.getOut_id() + " 主叫:" + callState.getCaller() + ",被叫:" + callState.getCallee());
                        String result = startRecord(callState.getOut_id());

                        if (result.equals(GlobalStatic.FAIL)) {
                            logger.info("freeswitch录音异常: sessionId:" + callState.getOut_id() + " 主叫:" + callState.getCaller() + ",被叫:" + callState.getCallee());
                        }

                        msgMap.put(Constants.WEB_SOCKET_JSON_KEY_MSG_TYPE, Constants.WEB_SOCKET_MSG_TYPE_MAIN_ANSWERED);
                        redisSaveMap.put(RedisFields.CALL_HISTORY_MAIN_CALL_ANSWERED, Constants.TRUE);
                        redisSaveMap.put(RedisFields.CALL_HISTORY_MAIN_CALL_ANSWERED_TIME, DateUtils.stringFromString(callState.getStatus_time(), DateUtils.DATE_FORMAT_DATETIME_SSS));
                        redisSaveMap.put(RedisFields.RECEIVE_HISTORY_MAIN_CALL_ANSWERED_TIME, nowDateStr);


                    } else if (callState.getDestinationNumber().equals(callState.getCallee())) { //呼叫建立，正在通话(被叫应答)

                        msgMap.put(Constants.WEB_SOCKET_JSON_KEY_MSG_TYPE, Constants.WEB_SOCKET_MSG_TYPE_TARGET_ANSWERED);

                        redisSaveMap.put(RedisFields.CALL_HISTORY_TARGET_CALL_ANSWERED, Constants.TRUE);
                        redisSaveMap.put(RedisFields.CALL_HISTORY_TARGET_CALL_ANSWERED_TIME, DateUtils.stringFromString(callState.getStatus_time(), DateUtils.DATE_FORMAT_DATETIME_SSS));
                        redisSaveMap.put(RedisFields.RECEIVE_CALL_HISTORY_TARGET_CALL_ANSWERED_TIME, nowDateStr);

                    }

                    break;

                case CHANNEL_HANGUP:   //呼叫结束 返回的呼叫状态
                    //客户不接->客户无接听
                    //客户挂断->客户挂机
                    //客户接->结束通话
                    try {
                        if (callHistoryMap.get(RedisFields.CALL_HISTORY_DISCONNECT_TIME) == null) {//单呼只有一条通道可以不用判断，但是双呼有两条通道
                            //通话结束状态回来以后将该使用用户的繁忙状态改为否
                            if (callHistoryMap.get(RedisFields.CREATE_USER_ID) != null) {
                                redisTemplate.opsForHash().put(RedisKey.USER_BUSY, callHistoryMap.get(RedisFields.CREATE_USER_ID), Constants.FALSE);
                            }
                            redisSaveMap.put(RedisFields.CALL_HISTORY_DISCONNECT_TIME, DateUtils.stringFromString(callState.getStatus_time(), DateUtils.DATE_FORMAT_DATETIME_SSS));
                            redisSaveMap.put(RedisFields.RECEIVE_CALL_HISTORY_DISCONNECT_TIME, nowDateStr);

                            if (!Constants.TRUE.equals(callHistoryMap.get(RedisFields.CALL_HISTORY_MAIN_CALL_ANSWERED))&&!Constants.TRUE.equals(callHistoryMap.get(RedisFields.CALL_HISTORY_TARGET_CALL_ANSWERED))) { //呼叫经纪失败，（各种原因）

                                msgMap.put(Constants.WEB_SOCKET_JSON_KEY_MSG_TYPE, Constants.WEB_SOCKET_MSG_TYPE_TARGET_FAILED);
                                msgMap.put(Constants.WEB_SOCKET_JSON_KEY_DESC, Constants.FJ_TELECOM_FAILED_REASON_TARGET_FAILED_4);

                                redisSaveMap.put(RedisFields.CALL_HISTORY_TARGET_CALL_FAILED, Constants.TRUE);
                                redisSaveMap.put(RedisFields.CALL_HISTORY_TARGET_CALL_FAILED_TIME, DateUtils.stringFromString(callState.getStatus_time(), DateUtils.DATE_FORMAT_DATETIME_SSS));
                                redisSaveMap.put(RedisFields.RECEIVE_CALL_HISTORY_TARGET_CALL_FAILED_TIME, nowDateStr);

                            } else if (!Constants.TRUE.equals(callHistoryMap.get(RedisFields.CALL_HISTORY_MAIN_CALL_ANSWERED_TIME))) { //呼叫客户失败（各种原因）

                                msgMap.put(Constants.WEB_SOCKET_JSON_KEY_MSG_TYPE, Constants.WEB_SOCKET_MSG_TYPE_MAIN_FAILED);
                                msgMap.put(Constants.WEB_SOCKET_JSON_KEY_DESC, Constants.FJ_TELECOM_FAILED_REASON_MAIN_FAILED_5);

                                redisSaveMap.put(RedisFields.CALL_HISTORY_MAIN_CALL_FAILED, Constants.TRUE);
                                redisSaveMap.put(RedisFields.CALL_HISTORY_MAIN_CALL_FAILED_TIME, DateUtils.stringFromString(callState.getStatus_time(), DateUtils.DATE_FORMAT_DATETIME_SSS));
                                redisSaveMap.put(RedisFields.RECEIVE_CALL_HISTORY_MAIN_CALL_FAILED_TIME, nowDateStr);

                            } else { //正常通话结束
                                msgMap.put(Constants.WEB_SOCKET_JSON_KEY_MSG_TYPE, Constants.WEB_SOCKET_MSG_TYPE_MAIN_DISCONNECTED);

                                //这里生产录音url ，因为只有正常通话才有录音
                                try {
                                    Object recordFilePath = redisTemplate.opsForHash().get(RedisKey.CALL_HISTORY_RPIX + callState.getSessionId() + "_temp", "recordFilePath");

                                    if (StringUtil.isNotNull(recordFilePath)) { //不为空有文件，将Url 放入redis
                                        redisSaveMap.put(RedisFields.CALL_HISTORY_RECORD_FILE_URL,recordFilePath.toString());
                                        logger.info("freeswitchLog :  生成freeswitch录音文件url:" ,recordFilePath.toString());
                                        redisTemplate.delete(RedisKey.CALL_HISTORY_RPIX + callState.getSessionId() + "_temp");//取了以后删除key
                                    }
                                }catch (Exception e){
                                    logger.error(">>>生成录音文件url异常");
                                }

                            }
                        }

                    } catch (Exception e) { //防止话单比结束状态早回来的情况
                        msgMap.put(Constants.WEB_SOCKET_JSON_KEY_MSG_TYPE, Constants.WEB_SOCKET_MSG_TYPE_MAIN_DISCONNECTED);
                    }

                    break;
                case CUSTOM:
                    String subclass = event.getEventHeaders().get("Event-Subclass");
                    freeswitchCustomEvent(subclass,msgMap,redisSaveMap);
                    break;
                default:
                    //多余状态不推送到客户端
                    msgMap.put(Constants.WEB_SOCKET_JSON_KEY_MSG_TYPE, Constants.WEB_SOCKET_MSG_TYPE_INVALID);
                    break;

            }

            //如果中断，后续的数据不发送到客户端
            if (redisTemplate.opsForValue().get(RedisKey.INTERRUPT_FAIL + callHistoryMap.get(RedisFields.CALL_HISTORY_SESSION_ID)) != null) {

                redisSaveMap.put(RedisFields.CALL_HISTORY_REMARK, Constants.LOCAL_MSG_CALL_CANCEL);
                msgMap.put(Constants.WEB_SOCKET_JSON_KEY_MSG_TYPE, Constants.WEB_SOCKET_MSG_TYPE_INVALID);
            }


        } else if (callState.getMsgType().equals(AliyunAkInfo.VOICEREPORT)) {//呼出话务单话务单回来之后才推送给持久化服务


            //手动取消外呼显示取消外呼
            logger.info("fscall------------------INTERRUPT：{}", callHistoryMap.get(RedisFields.INTERRUPT));

            if (callHistoryMap.get(RedisFields.INTERRUPT) != null
                    && Constants.INTERRUPT.toString().equals(callHistoryMap.get(RedisFields.INTERRUPT))) {
                redisSaveMap.put(RedisFields.CALL_HISTORY_FAILED_REASON, Constants.LOCAL_MSG_CALL_CANCEL);

            }

            if (StringTools.isNotempty(callState.getA_duration())) { //主叫时长

                redisSaveMap.put(RedisFields.MAIN_CALL_LENGTH, callState.getA_duration());

                //通话时长,目前取主叫的通话时长（所有主叫均为客户）
                redisSaveMap.put(RedisFields.CALL_HISTORY_RECORD_TIME_LENTH, callState.getA_duration());

            }

            if (StringTools.isNotempty(callState.getA_start_time())) { // 主叫开始时间可

                redisSaveMap.put(RedisFields.MAIN_CALL_START_TIME, callState.getA_start_time());
            }

            if (StringTools.isNotempty(callState.getA_end_time())) { // 主叫结束时间

                redisSaveMap.put(RedisFields.MAIN_CALL_END_TIME, callState.getA_end_time());
            }

            if (StringTools.isNotempty(callState.getDuration())) { //被叫通话时长可能没有这个时间
                redisSaveMap.put(RedisFields.TARGET_CALL_LENGTH, callState.getDuration());
            }

            if (StringTools.isNotempty(callState.getStart_time())) { //被叫开始时间

                redisSaveMap.put(RedisFields.TARGET_CALL_START_TIME, callState.getStart_time());
            }
            if (StringTools.isNotempty(callState.getEnd_time())) { //被叫结束时间可能没有这个时间

                redisSaveMap.put(RedisFields.TARGET_CALL_END_TIME, callState.getEnd_time());
            }
            //话务单回来也不需要发送到客户端
            msgMap.put(Constants.WEB_SOCKET_JSON_KEY_MSG_TYPE, Constants.WEB_SOCKET_MSG_TYPE_INVALID);

        }

        msgMap.put(Constants.WEB_SOCKET_JSON_KEY_TIME, nowDateStr);
        msgMap.put(Constants.WEB_SOCKET_JSON_KEY_SESSION_ID, callState.getSessionId());
        msgMap.put(Constants.WEB_SOCKET_JSON_KEY_DATA_ID, callHistoryMap.get(RedisFields.CALL_HISTORY_DATA_ID));
        msgMap.put(Constants.WEB_SOCKET_JSON_KEY_PAGE_FROM, callHistoryMap.get(RedisFields.CALL_HISTORY_PAGE_FROM));
        msgMap.put(Constants.WEB_SOCKET_JSON_KEY_MACHINE_FROM, callHistoryMap.get(RedisFields.CALL_HISTORY_MACHINE_FROM));

        resultMap.put(Constants.CALL_STATE_WORK_HANDLER_MAP_KEY_MSG, msgMap);
        resultMap.put(Constants.CALL_STATE_WORK_HANDLER_MAP_KEY_REDIS, redisSaveMap);

        return resultMap;

    }

    /**
     * 推送到websocket
     *
     * @param callHistoryMap
     * @param resultMap
     * @throws Exception
     */
    private void pushStateToClient(Map<String, String> callHistoryMap, Map<String, Map<String, String>> resultMap) throws Exception {
        Map<String, String> msgMap = resultMap.get(Constants.CALL_STATE_WORK_HANDLER_MAP_KEY_MSG);
        String sessionId = callHistoryMap.get(Constants.WEB_SOCKET_JSON_KEY_SESSION_ID);

        //呼入暂时不推送数据到客户端
        if (Constants.IN_COME.toString().equals(callHistoryMap.get(RedisFields.CALL_HISTORY_CALL_TYPE))
                || Constants.WEB_SOCKET_MSG_TYPE_INCOME.equals(msgMap.get(Constants.WEB_SOCKET_JSON_KEY_MSG_TYPE))) {
            logger.debug("ivr INCOME msg,dont send to client");
            return;
        }
        if (Constants.WEB_SOCKET_MSG_TYPE_INVALID.equals(msgMap.get(Constants.WEB_SOCKET_JSON_KEY_MSG_TYPE))) {
            logger.debug("ivr INVALID msg, dont send to client");
            return;
        }

        String json = JSONObject.toJSONString(msgMap);

        logger.debug("ivr FreeswitchStateWorkHandler pushStateToClient--->data:" + json);

        String rs = webSocketUtils.pushToClientBySessionId(sessionId, json);
        if (Constants.FAIL.equals(rs) || rs == null)
            logger.error("ivr fscallCallStateWorkHandler pushStateToClient--->rs:{},sessionId:{}", rs, sessionId);
    }

    /**
     * 将呼叫消息推送到ES和
     *
     * @param callHistoryMap
     */
    private void todoSaveCallRcord(Map<String, String> callHistoryMap) {
        try {
            String jsonStr = JSONObject.toJSONString(callHistoryMap);
            pushDataToEsTaskExecutor.execute(() -> {
                pushDataToEsBiz.pushCallHistoryToEs(callHistoryMap.get(RedisFields.CALL_HISTORY_SESSION_ID), jsonStr,false);
            });

        } catch (Exception e) {
            try {
                redisTemplate.opsForSet().add(RedisKey.PUSH_TO_ES_FAILED_HISTORY, callHistoryMap.get(RedisFields.CALL_HISTORY_SESSION_ID));
            } catch (Exception e1) {
                logger.error("将推送ES 失败数据放入redis 失败！sessionId：{}", callHistoryMap.get(RedisFields.CALL_HISTORY_SESSION_ID), e1);
            }
            logger.error("====>推送Es 的线程池爆了", e);
        }
    }

    /**
     * 将呼叫消息推送到置业Oracle
     *
     * @param callHistoryMap
     */
    private void pushCallRcordToOracle(Map<String, String> callHistoryMap) {

        try {
            pushDataToOracleTaskExecutor.execute(() -> {
                pushDataToOracleBiz.pushData(callHistoryMap);
            });
        } catch (Exception e) {
            logger.error("====>推送置业Oracle失败", e);
            pushDataToOracleBiz.setReids("record",callHistoryMap.get(RedisFields.CALL_HISTORY_SESSION_ID));
        }

    }

    /**
     * 录音操作
     *
     * @param channelUUid
     */
    public String startRecord(String channelUUid) {

        try {

            SendMsg msg = new SendMsg(channelUUid);
            msg.addCallCommand("execute");
            msg.addExecuteAppName("record_session");
            String filePath = "${strftime(%Y%m%d)}/${uuid}.wav";
            String fileUrl = DateUtils.formatDate(new Date(), "yyyyMMdd")+"/"+channelUUid+".wav";
            msg.addExecuteAppArg(recordFilePath + filePath);
            redisTemplate.opsForHash().put(RedisKey.CALL_HISTORY_RPIX + channelUUid + "_temp", "recordFilePath", fileUrl);
            // msg.addExecuteAppArg("$${base_dir}/recordings/${strftime(%Y%m%d)}/${uuid}.wav");
            //有效时间为一天
            redisTemplate.expire(RedisKey.CALL_HISTORY_RPIX + channelUUid + "_temp", RedisTimeOut.CACHE_ONE_DAY, TimeUnit.SECONDS);
            eventInitBean.getClient().sendMessage(msg);

            return GlobalStatic.SUCCESS;

        } catch (Exception e) {

            e.printStackTrace();

            return GlobalStatic.FAIL;
        }

    }

    /**
     * 呼入通过packageId获取开场白
     * @param packageId
     */
    private Map<String,String> getVoiceMapByPackageId(String packageId){
        Map<String,String> resultMap = new HashMap<>();
        try {
            MultiValueMap<String, Object> requestParam = new LinkedMultiValueMap<>();
            requestParam.set("packageId", packageId);
            // 通过 HttpHeaders 设置Form方式提交
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(APPLICATION_FORM_URLENCODED);
            HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity<MultiValueMap<String, Object>>(requestParam, headers);
            Map map = restTemplate.postForObject(linkcallWebUrl + "/linkageCall/getVoiceMapByPackageId", httpEntity, Map.class);
            logger.info("通过packageId调用查询开场白服务返回：{}",JSONObject.toJSONString(map));
            if (map != null && !map.isEmpty() && GlobalStatic.CODE_1.equals(map.get("code")) && map.containsKey("data")) {
                Map<String, Object> dataMap = (Map<String, Object>) map.get("data");
                if (dataMap != null && !dataMap.isEmpty()) {
                    resultMap.put("voiceCode",(String) dataMap.get("voiceCode"));
                }
            }
        }catch (Exception e){
            logger.error("获取任务包异常，错误信息：{}",e);
        }
        return resultMap;
    }
}
